

package com.code.ape.codeape.common.security.service;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.code.ape.codeape.admin.api.dto.UserInfo;
import com.code.ape.codeape.admin.api.entity.SysUser;
import com.code.ape.codeape.admin.api.feign.RemoteUserService;
import com.code.ape.codeape.common.core.constant.CacheConstants;
import com.code.ape.codeape.common.core.constant.CommonConstants;
import com.code.ape.codeape.common.core.constant.SecurityConstants;
import com.code.ape.codeape.common.core.util.MD5Util;
import com.code.ape.codeape.common.core.util.R;
import com.code.ape.codeape.common.core.util.RetOps;
import com.code.ape.codeape.device.api.entity.DeviceInfo;
import com.code.ape.codeape.device.api.feign.RemoteDeviceService;
import com.code.ape.codeape.device.api.vo.DeviceInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * 处理用户名、密码登录，PDA端
 * 自定义
 */
@Slf4j
@RequiredArgsConstructor
public class CodeapePDAUserDetailsServiceImpl implements CodeapeUserDetailsService {

	private final RemoteUserService remoteUserService;

	private final CacheManager cacheManager;

	private final RemoteDeviceService remoteDeviceService;



	/**
	 * 用户名密码登录
	 * @param username 用户名
	 * @return
	 */
	@Override
	@SneakyThrows
	public UserDetails loadUserByUsername(String username) {
		Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
		if (cache != null && cache.get(username) != null) {
			return (CodeapeUser) cache.get(username).get();
		}

		R<UserInfo> result = remoteUserService.info(username);
		UserDetails userDetails = getUserDetails(result);
		if (cache != null) {
			cache.put(username, userDetails);
		}
		return userDetails;
	}

	@Override
	public int getOrder() {
		return Integer.MIN_VALUE;
	}

	/**
     * 仅仅支持WEB的密码模式登录
	 * @param clientId 目标客户端
     * @param grantType  授权类型
     */
	@Override
	public boolean support(String clientId, String grantType) {
		return StrUtil.equals(clientId,SecurityConstants.PDA)&&StrUtil.equals(grantType,"password");
	}

	@Override
	public UserDetails loadUserByUsernameAndOther(String username, String... others) throws UsernameNotFoundException {
		String sn=others[0];
		Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
		String key= MD5Util.encrypt(MessageFormat.format(CacheConstants.USER_DETAILS_INFO,username,sn));
		if (cache != null && cache.get(key) != null) {
			return (CodeapeUser) cache.get(key).get();
		}

		//获取设备的详细信息
		R<DeviceInfoVO> deviceResult = remoteDeviceService.getBySn(sn);
		DeviceInfoVO deviceInfo = RetOps.of(deviceResult).getData().orElseThrow(() -> new UsernameNotFoundException("设备不存在"));
		R<UserInfo> result = remoteUserService.loadInfoByUserNameAndHosId(username,deviceInfo.getHosId());
		UserDetails userDetails = getUserDetails(result,deviceInfo,SecurityConstants.PDA,sn);
		if (cache != null) {
			cache.put(key, userDetails);
		}
		return userDetails;
	}

	@Override
	public UserDetails loadUserByUser(CodeapeUser codeapeUser) {
		return this.loadUserByUsernameAndOther(codeapeUser.getUsername(),codeapeUser.getSn());
	}


	@Override
	public UserDetails getUserDetails(R<UserInfo> result, DeviceInfoVO deviceInfoVO, String clientId, String sn) {
		UserInfo info = RetOps.of(result).getData().orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

		Set<String> dbAuthsSet = new HashSet<>();

		if (ArrayUtil.isNotEmpty(info.getRoles())) {
			// 获取角色
			Arrays.stream(info.getRoles()).forEach(role -> dbAuthsSet.add(SecurityConstants.ROLE + role));
			// 获取资源
			dbAuthsSet.addAll(Arrays.asList(info.getPermissions()));
		}

		//封装科室权限：用户的权限+设备的权限，todo: 此处需要采用Set过滤，存在用户的权限和科室的权限重复的场景
		Long[] deptAuths = ArrayUtil.addAll(info.getDeptAuths(), deviceInfoVO.getDeptAuths().toArray(new Long[]{}));


		Collection<GrantedAuthority> authorities = AuthorityUtils
				.createAuthorityList(dbAuthsSet.toArray(new String[0]));
		SysUser user = info.getSysUser();

		//角色集合
		String[] roleCodes = info.getRoleList().stream().map(data-> SecurityConstants.ROLE+data.getRoleCode()).toArray(String[]::new);

		// 构造security用户
		return new CodeapeUser(user.getUserId(), user.getDeptId(), user.getUsername(),
				SecurityConstants.BCRYPT + user.getPassword(), user.getPhone(), true, true, true,
				StrUtil.equals(user.getLockFlag(), CommonConstants.STATUS_NORMAL),info.getHosId(),deptAuths,roleCodes,authorities,clientId,sn);
	}
}
